// 建立模板和节点之间的映射

import { getValue } from "../util/ObjectUtil.js";

// 可以通过模板，找到哪些节点用到了这个模板
let template2Vnode = new Map();
// 可以通过节点，找到这个节点下有哪些模板
let vnode2Template = new Map();
// 预备渲染（创建渲染索引）
function analysisTemplateString(vnode) {
  let templateStrList = vnode.text.match(/{{[a-zA-Z0-9_.]+}}/g);
  // debugger;
  for (let i = 0; templateStrList && i < templateStrList.length; i++) {
    // 设置模板与虚拟dom的映射关系
    // debugger
    setTemplate2Vnode(templateStrList[i], vnode);
    setVnode2Template(templateStrList[i], vnode);
  }
}
// 建立映射关系方法
function setTemplate2Vnode(template, vnode) {
  // debugger
  let templateName = getTemplateName(template);
  let templateSet = template2Vnode.get(templateName);
  if (templateSet) {
    templateSet.push(vnode);
  } else {
    template2Vnode.set(templateName, [vnode]);
  }
}
function setVnode2Template(template, vnode) {
  let templateName = getTemplateName(template);
  let vnodeSet = vnode2Template.get(vnode);
  if (vnodeSet) {
    vnodeSet.push(templateName);
  } else {
    vnode2Template.set(vnode, [templateName]);
  }
}
// 解花括号方法
function getTemplateName(template) {
  // 判断是否有花括号，如果有，则解掉，如果没有直接返回
  if (
    template.substring(0, 2) === "{{" &&
    template.substring(template.length - 2, template.length) === "}}"
  ) {
    // 有花括号
    return template.substring(2, template.length - 2);
  } else {
    return template;
  }
}
function renderNode(vm, vnode) {
  // 渲染文本节点方法
  // debugger
  if (vnode.nodeType === 3) {
    // debugger;
    // 文本节点
    let templates = vnode2Template.get(vnode);
    if (templates) {
      let result = vnode.text; // 获取文本节点的文本内容(没去双花括号的时候)
      for (let i = 0; i < templates.length; i++) {
        // 获取的数据源之所以是一个数组[vm._data, vnode.env],而不是单一的vm._data是因为在v-for中数据源会来自父级节点的环境，所以要传当前变量vnode.env和全局变量vm._data
        let templateValue = getTemplateValue(
          [vm._data, vnode.env],
          templates[i]
        );
        if (templateValue) {
          // 如果数据源中有相应的数据就进行模板文本替换
          result = result.replace("{{" + templates[i] + "}}", templateValue);
        }
        vnode.elm.nodeValue = result; // 给vnode节点设置新的文本
        //console.log(templateValue);
      }
    }
  } else if (vnode.nodeType === 1 && vnode.tag === "INPUT") {
    // 带有v-model的input框
    // debugger
    let templates = vnode2Template.get(vnode); // 当前节点关联了多少模板(对于input节点来说如果有也只可能是一个模板)
    if (templates) {
      for (let i = 0; i < templates.length; i++) {
        let templateValue = getTemplateValue(
          [vm._data, vnode.env],
          templates[i]
        );
        if (templateValue) {
          vnode.elm.value = templateValue;
        }
      }
    }
  } else {
    // 如果不是文本节点就向下递归
    for (let i = 0; i < vnode.children.length; i++) {
      renderNode(vm, vnode.children[i]);
    }
  }
}
function getTemplateValue(objs, templateName) {
  // 获取模板值方法
  // 获取形如key.a.b.c的值的方法
  let len = objs.length;
  for (let i = 0; i < len; i++) {
    let temp = getValue(objs[i], templateName);
    if (temp != null) {
      return temp;
    }
  }
  return null;
}
function analysisAttr(vm, vnode) {
  // 分析属性
  if (vnode.nodeType !== 1) {
    return false; // 如果不是标签节点就不可能有属性
  }
  let attrNames = vnode.elm.getAttributeNames();
  if (attrNames.indexOf("v-model") > -1) {
    // 把带有v-model属性的标签中的数据也建立模板数据间的相互映射
    setTemplate2Vnode("{{" + vnode.elm.getAttribute("v-model") + "}}", vnode);
    setVnode2Template("{{" + vnode.elm.getAttribute("v-model") + "}}", vnode);
  }
}

export function renderMixin(Due) {
  Due.prototype._render = function () {
    renderNode(this, this._vnode);
  };
}

export function prepareRender(vm, vnode) {
  // 预渲染建立映射关系
  if (vnode === null) {
    return false; // 如果传入的根节点为空就什么也不干
  } else if (vnode.nodeType === 0) {
    // 虚拟节点，这里主要针对的是v-for产生的虚拟节点
    setTemplate2Vnode("{{" + vnode.data + "}}", vnode);
    setVnode2Template("{{" + vnode.data + "}}", vnode);
  } else if (vnode.nodeType === 1) {
    // 标签节点
    analysisAttr(vm, vnode); // 如果是标签节点就先进行属性分析(分析有没有类似v-model的属性)
  } else if (vnode.nodeType === 3) {
    // debugger;
    // 如果当前是文本，则解析是否存在模板
    analysisTemplateString(vnode); // 分析模板字符串
  }
  for (let i = 0; i < vnode.children.length; i++) {
    prepareRender(vm, vnode.children[i]);
  }
}
export function getTemplate2VnodeMap() {
  return template2Vnode;
}
export function getVnode2TemplateMap() {
  return vnode2Template;
}
export function renderData(vm, data) {
  // 在模板上重新渲染被更改的数据
  let vnodes = template2Vnode.get(data);
  if (vnodes != null) {
    let len = vnodes.length;
    for (let i = 0; i < len; i++) {
      // 重新渲染节点
      renderNode(vm, vnodes[i]);
    }
  }
}

export function getVNodeByTemplate(template) {
  // 通过模板获取虚拟节点
  return template2Vnode.get(template);
}

export function clearMap() {
  // 由于v-for的改变导致所有的节点和模板对应关系都需要改变
  template2Vnode.clear();
  vnode2Template.clear();
}
